package com.moss.cloud.base.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.moss.cloud.base.api.model.from.BaseFrom;
import com.moss.cloud.base.api.model.from.ChildrenFrom;
import com.moss.cloud.base.api.model.from.RegionFrom;
import com.moss.cloud.base.api.model.param.RegionTreeParam;
import com.moss.cloud.base.biz.event.RegionChangeEvent;
import com.moss.cloud.base.biz.mapper.SysProvincesMapper;
import com.moss.cloud.base.biz.model.SysProvinces;
import com.moss.cloud.base.biz.service.ISysProvincesService;
import com.moss.cloud.common.base.utils.PageUtil;
import com.moss.cloud.common.core.enums.ChangeTypeEnum;
import com.moss.cloud.common.core.enums.DictCacheEnum;
import com.moss.cloud.common.core.enums.state.Deleted;
import com.moss.cloud.common.core.exception.SystemErrorType;
import com.moss.cloud.common.core.model.vo.RegionTreeVO;
import com.moss.cloud.common.core.utils.BooleanHandel;
import com.moss.cloud.common.core.utils.SpringContextHolder;
import com.moss.cloud.common.core.utils.TreeUtil;
import com.moss.cloud.common.security.component.RedisTemplateOps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 全国行政区划业务实现
 *
 * @author 瑾年
 * @date 2023年12月2日
 */
@Slf4j
@Service
public class SysProvincesServiceImpl extends ServiceImpl<SysProvincesMapper, SysProvinces> implements ISysProvincesService {
    private RedisTemplateOps redisTemplateOps;

    public SysProvincesServiceImpl(RedisTemplateOps redisTemplateOps) {
        this.redisTemplateOps = redisTemplateOps;
    }

    /**
     * 数据缓存初始化
     */
    @Override
    public List<RegionTreeVO> loadProvinces() {
        List<SysProvinces> province = this.list(new QueryWrapper<SysProvinces>().lambda().notIn(SysProvinces::getDeleted, Deleted.deleteds(Deleted.DELETE.code())));
        List<RegionTreeVO> regionList = CollectionUtils.isNotEmpty(province) ? province.stream().map(this::regionTree)
                .collect(Collectors.toList()) : Collections.emptyList();
        List<RegionTreeVO> tree = TreeUtil.toTree(regionList, 100000L, RegionTreeVO::getId, RegionTreeVO::getParentId, RegionTreeVO::setChildren);
        redisTemplateOps.set(DictCacheEnum.DISTRICT.getKey() + DictCacheEnum.PROVINCE.getKey(), tree);
        return tree;
    }

    /**
     * 查询行政区划数据
     *
     * @return
     */
    @Override
    public List<RegionTreeVO> regionTrees() {
        boolean hasKey = redisTemplateOps.hasKey(DictCacheEnum.DISTRICT.getKey() + DictCacheEnum.PROVINCE.getKey());
        return hasKey ? (List<RegionTreeVO>) redisTemplateOps.get(DictCacheEnum.DISTRICT.getKey() + DictCacheEnum.PROVINCE.getKey()) : this.loadProvinces();
    }

    /**
     * 查询行政区划数据
     *
     * @return
     */
    @Override
    public IPage<RegionTreeVO> regionPageTree(RegionTreeParam param) {
        Page<SysProvinces> page = PageUtil.createPage(param.getCurrent(), param.getSize());
        IPage<SysProvinces> provincesIPage = this.page(page, new QueryWrapper<SysProvinces>().lambda()
                .like(StringUtils.isNotBlank(param.getCityName()), SysProvinces::getCityName, param.getCityName())
                .like(StringUtils.isNotBlank(param.getShortName()), SysProvinces::getShortName, param.getShortName())
                .like(StringUtils.isNotBlank(param.getPinyin()), SysProvinces::getPinyin, param.getPinyin())
                .notIn(SysProvinces::getDeleted, Deleted.deleteds(Deleted.DELETE.code()))
                .eq(SysProvinces::getParentId, 100000L));
        IPage<RegionTreeVO> provincesPage = new Page<>();
        List<RegionTreeVO> regionTreeVOList = CollectionUtils.isNotEmpty(provincesIPage.getRecords()) ? provincesIPage.getRecords()
                .stream().map(this::regionTree).collect(Collectors.toList()) : Collections.emptyList();
        BeanUtils.copyProperties(provincesIPage, provincesPage);
        provincesPage.setRecords(regionTreeVOList);
        return provincesPage;
    }

    /**
     * 查询行政区子集数据查询
     *
     * @param childrenFrom
     * @return
     */
    @Override
    public List<RegionTreeVO> regionChildren(ChildrenFrom childrenFrom) {
        List<SysProvinces> provinces = this.list(new QueryWrapper<SysProvinces>().lambda()
                .eq(SysProvinces::getParentId, childrenFrom.getParentId()));
        return CollectionUtils.isNotEmpty(provinces) ? provinces.stream().map(this::regionTree)
                .collect(Collectors.toList()) : Collections.emptyList();
    }

    private RegionTreeVO regionTree(SysProvinces provinces) {
        RegionTreeVO regionTreeVO = new RegionTreeVO();
        BeanUtils.copyProperties(provinces, regionTreeVO);
        regionTreeVO.setIsLeaf(provinces.getDepth() == 3 ? Boolean.TRUE : Boolean.FALSE);
        return regionTreeVO;
    }

    /**
     * 新增行政区划
     *
     * @param regionFrom
     * @return
     */
    @Override
    public Boolean saveRegion(RegionFrom regionFrom) {
        boolean saveFlag = this.save(this.provinces(regionFrom, Boolean.TRUE));
        SpringContextHolder.publishEvent(new RegionChangeEvent(this, ChangeTypeEnum.SYS_REGION_CHANGE.getType()));
        return saveFlag;
    }

    /**
     * 编辑行政区划
     *
     * @param regionFrom
     * @return
     */
    public Boolean updateRegion(RegionFrom regionFrom) {
        BooleanHandel.trueThrow(Objects.isNull(regionFrom.getId())).throwMessage(SystemErrorType.PRIMARY_KEY);
        boolean updateFlag = this.updateById(this.provinces(regionFrom, Boolean.FALSE));
        SpringContextHolder.publishEvent(new RegionChangeEvent(this, ChangeTypeEnum.SYS_REGION_CHANGE.getType()));
        return updateFlag;
    }

    /**
     * 数据转换
     *
     * @param regionFrom
     * @param isAdd
     * @return
     */
    private SysProvinces provinces(RegionFrom regionFrom, Boolean isAdd) {
        this.checkRegionData(regionFrom, isAdd);
        SysProvinces sysProvinces = new SysProvinces();
        BeanUtils.copyProperties(regionFrom, sysProvinces);
        return sysProvinces;
    }

    /**
     * 删除行政区划
     *
     * @param baseFrom
     * @return
     */
    public Boolean removeRegion(BaseFrom baseFrom) {
        SysProvinces provinces = this.getById(baseFrom.getId());
        BooleanHandel.trueThrow(Objects.isNull(provinces)).throwMessage(SystemErrorType.DATE_EMPTY);
        List<SysProvinces> provincesList = this.list(new QueryWrapper<SysProvinces>().lambda()
                .eq(SysProvinces::getParentId, baseFrom.getId()));
        BooleanHandel.trueThrow(CollectionUtils.isNotEmpty(provincesList)).throwMessage(SystemErrorType.CHILDREN_NOT_EMPTY);
        boolean removeFlag = this.removeById(baseFrom.getId());
        SpringContextHolder.publishEvent(new RegionChangeEvent(this, ChangeTypeEnum.SYS_REGION_CHANGE.getType()));
        return removeFlag;
    }

    /**
     * 行政编码重复性验证
     *
     * @param regionFrom
     * @param isAdd
     */
    private void checkRegionData(RegionFrom regionFrom, Boolean isAdd) {
        BooleanHandel.isTrue(StringUtils.isNotBlank(regionFrom.getZipCode())).trueHandle(() -> {
            List<SysProvinces> provinces = this.list(new QueryWrapper<SysProvinces>().lambda()
                    .eq(SysProvinces::getZipCode, regionFrom.getZipCode()));
            BooleanHandel.trueThrow(isAdd.equals(Boolean.TRUE) && CollectionUtils.isNotEmpty(provinces)).throwMessage(SystemErrorType.ZIP_CODE_REPEAT);
            BooleanHandel.isTrue(isAdd.equals(Boolean.FALSE)).trueHandle(() -> {
                provinces.removeIf(item -> item.getId().equals(regionFrom.getId()));
                BooleanHandel.trueThrow(CollectionUtils.isNotEmpty(provinces)).throwMessage(SystemErrorType.ZIP_CODE_REPEAT);
            });
        });
    }

}
